Repository navigation
Conversation
Port of the AdjointEuropeanEquityOption C++ example. Prices a portfolio of European put options (10 underlyings, strikes 10-79) over a zero curve and a black variance curve, and computes the sensitivities of the total value to all 98 market inputs (zero rates, volatilities, strikes, underlyings, dividend yield) in a single adjoint pass. The largest sensitivities are cross-checked against bump-and-reprice finite differences inside the example itself.
|
|
|
Thanks a lot for these, Tyler! Could you sign the CLA (link above)? Then we can run CI and review all four. |
auto-differentiation-dev
left a comment
There was a problem hiding this comment.
Thanks for picking up #15, and for porting the full portfolio rather than a single option: that's a nice first example for new users. A few things before we can merge:
- Run it on QuantLibAAD. QuantLibAAD 1.44.0 is now on PyPI (
pip install QuantLibAAD, Python 3.10–3.14), so the example can now be run against the package it's for. - Rebase onto current
main. Your branch is based on the state before 1.44.0, so the diff currently shows the whole release. After the rebase it should only addPython/examples/european-option-adjoint.pyand one CHANGELOG line. - Central differences for the check. Bump each input up and down,
(V(x+h) - V(x-h)) / (2h)withh = 1e-5, so the comparison agrees to about 1e-8 relative instead of 1e-5. Print the largest relative difference over all 98 inputs, not just the largest sensitivities. - Put the AAD computation in a function, as the newer examples do: see
aad_sensitivities()inPython/examples/trade-risk.py. Here it would return the portfolio value and a dict of sensitivities keyed by input name (e.g."rate 1999-04-27","strike 40","underlying 36","dividend yield"), and the script calls it and prints the results as now. That keeps the examples consistent and lets readers reuse the calculation from their own code or a notebook. - CHANGELOG: add a line under
## [Unreleased]/### Added, e.g. "Exampleeuropean-option-adjoint.py: sensitivities of a European option portfolio to all market inputs in one adjoint pass". - CLA: please sign it (link in the CLA check on this PR); we can't merge before it's signed.
The same points apply to #24, #25 and #26 (run on QuantLibAAD 1.44.0, rebase, central-difference check over all inputs, an aad_sensitivities() function, a CHANGELOG line each), so please work through them there too, rather than us repeating them. Two things specific to those:
- #24 (American option): QuantLibAAD 1.44.0 fixes the zero dividend rho with finite-difference engines that your notes describe, so on 1.44.0 the adjoint dividend rho should match the bumped one. Please remove that caveat from the example and include the dividend yield in the check.
- #26 (Heston): please run the calibration with
COSHestonEngineas written, rather than the analytic engine you used locally, and include all sensitivities in the check, not only the eight largest.
Once these are in, we'll run our checks and review all four again.
Closes #15.
Python port of the
AdjointEuropeanEquityOptionC++ example, following the pattern ofswap-adjoint.py:Testing: the current
QuantLibAADwheel is not reachable from my sandbox, so I ran the identical example code against QuantLib-Risks 1.33.3 (the direct predecessor of QuantLibAAD, same QuantLib/XAD lineage; only the tape-construction lines differ between the two APIs). It runs end to end: portfolio value 9481.90744, and the bump check agrees with the adjoints to about 1e-5 relative on the largest sensitivities (e.g. rate 27 Apr 1999: adjoint -19535.2986 vs bump -19535.1486; dividend rho: 12510.6614 vs 12510.6791). Happy to adjust if CI/Binder shows any API drift.Note: this repo requires a signed CLA before merge (per CONTRIBUTING) — I understand it will be handled through the CLA flow.